<template>
  <div>
      <uploader
        :autoStart="false"
        :options="options"
        :file-status-text="statusText"
        class="uploader-example"
        @file-complete="fileComplete"
        @complete="complete"
        @file-success="fileSuccess"
        @files-added="filesAdded"
      >
            <uploader-unsupport></uploader-unsupport>
        <uploader-drop>
          <p>将文件拖放到此处以上传</p>
          <uploader-btn>选择文件</uploader-btn>
          <uploader-btn :attrs="attrs">选择图片</uploader-btn>
          <uploader-btn :directory="true">选择文件夹</uploader-btn>
        </uploader-drop>
        <uploader-files></uploader-files>
      </uploader>
      <br/>
      <el-button @click="allStart()" :disabled="disabled">全部开始</el-button>
      <el-button @click="allStop()" style="margin-left: 4px">全部暂停</el-button>
      <el-button @click="allRemove()" style="margin-left: 4px">全部移除</el-button>
  </div>
</template>

<script>
import { getToken } from '@/utils/auth'
import SparkMD5 from 'spark-md5'
import { simpleUpload } from '@/api/system/simpleUpload'

export default {
  name: 'simpleUploader',
  data() {
    return {
      skip: false,
      options: {
        target: process.env.VUE_APP_BASE_API + '/simpleUpload/chunk',
        // 开启服务端分片校验功能
        chunkSize: 20 * 1024 * 1024,
        testChunks: true,
        //剩余时间
        parseTimeRemaining: function(timeRemaining, parsedTimeRemaining) {
          return parsedTimeRemaining
            .replace(/\syears?/, '年')
            .replace(/\days?/, '天')
            .replace(/\shours?/, '小时')
            .replace(/\sminutes?/, '分钟')
            .replace(/\sseconds?/, '秒')
        },
        // 服务器分片校验函数
        checkChunkUploadedByResponse: (chunk, message) => {
          const result = JSON.parse(message)
          if (result.data.skipUpload) {
            //秒传
            this.skip = true
            return true
          }
          chunk.file.objectName = result.data.objectName;
          chunk.file.uploadId = result.data.uploadId;
          return (result.data.uploaded || []).indexOf(chunk.offset + 1) >= 0
        },
        headers: {
          Authorization: 'Bearer ' + getToken()
        },
        processParams: (params, file) => {
          return {
            ...params,
            objectName: file.objectName,
            uploadId: file.uploadId
          };
        }
      },
      attrs: {
        accept: 'image/*'
      },
      statusText: {
        success: '上传成功',
        error: '上传出错了',
        uploading: '上传中...',
        paused: '暂停中...',
        waiting: '等待中...',
        cmd5: '计算文件MD5中...'
      },
      fileList: [],
      disabled: true,
    }
  },
  watch: {
    fileList() {
      this.disabled = this.fileList.length === 0
    }
  },
  methods: {
    /**
     * 全部开始
     */
    allStart() {
      this.fileList.forEach((file) => {
        if (file.paused) {
          file.resume()
        }
      })
    },
    /**
     * 全部暂停
     */
    allStop() {
      this.fileList.forEach((file) => {
        if (!file.paused) {
          file.pause()
        }
      })
    },
    /**
     * 全部删除
     */
    allRemove() {
      this.fileList.forEach((file) => {
        file.cancel()
      })
      this.fileList = []
    },
    fileComplete(rootFile) {
      // 一个根文件（文件夹）成功上传完成。
      // console.log('fileComplete', rootFile)
      // console.log('一个根文件（文件夹）成功上传完成。')
    },
    complete() {
      // 上传完毕。
      // console.log('complete')
    },
    /**
     * 文件添加
     * @param file
     * @param fileList
     * @param event
     */
    filesAdded(files) {
      files.forEach((file) => {
        //添加文件
        this.fileList.push(file)
        this.computeMD5(file)
      })
    },
    /**
     * 计算MD5
     * @param file
     */
    computeMD5(file) {
      let fileReader = new FileReader()
      let time = new Date().getTime()
      let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
      let currentChunk = 0
      //分片大小
      const chunkSize = this.options.chunkSize
      //分片数
      let chunks = Math.ceil(file.size / chunkSize)
      //追加数组缓冲区。
      let spark = new SparkMD5.ArrayBuffer()
      // 文件状态设为"计算MD5"
      file.cmd5 = true //文件状态为“计算md5...”
      file.pause()
      loadNext()
      // 读取文件
      fileReader.onload = function(e) {
        spark.append(e.target.result)
        if (currentChunk < chunks) {
          currentChunk++
          loadNext()
          // 实时展示MD5的计算进度
          console.log(
            `第${currentChunk}分片解析完成, 开始第${
              currentChunk + 1
            } / ${chunks}分片解析`
          )
        } else {
          // MD5计算完成
          let md5 = spark.end()
          console.log(
            `MD5计算完毕：${file.name} \nMD5：${md5} \n分片：${chunks} 大小:${
              file.size
            } 用时：${new Date().getTime() - time} ms`
          )
          spark.destroy() //释放缓存
          file.uniqueIdentifier = md5 //将文件md5赋值给文件唯一标识
          file.cmd5 = false //取消计算md5状态
          file.resume() //开始上传
        }
      }
      // 读取文件出错
      fileReader.onerror = function() {
        this.$message.error(`文件${file.name}读取出错，请检查该文件`)
        file.cancel()
      }

      //读取方法
      function loadNext() {
        let start = currentChunk * chunkSize
        let end = start + chunkSize;
        (end > file.size) && (end = file.size)
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end))
      }
    },
    /**
     * 上传成功
     * @param rootFile
     * @param file
     * @param response
     * @param chunk
     */
    fileSuccess(rootFile, file, response, chunk) {
      const result = JSON.parse(response)
      if (result.code == 200 && !this.skip) {
        simpleUpload({ md5: file.uniqueIdentifier }).then(resp => {
          if (resp.code == 200) {
            this.$message({
              message: '上传成功',
              type: 'success'
            })
          }
        })
      } else {
        console.log('上传成功，不需要合并')
      }
      if (this.skip) {
        this.skip = false
      }
    }
  }
}
</script>

<style scoped>
.uploader-example {
  width: 100%;
  padding: 15px;
  margin: 0px auto 0;
  font-size: 12px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}

.uploader-example .uploader-btn {
  margin-right: 4px;
}

.uploader-example .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>
